#region imported Namespaces
using System;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
using BO = PHSRAG.Insight21.BusinessObjects;
using Utility = PHSRAG.Utility;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
#endregion

namespace PHSRAG.Insight21.Purchasing
{
	/// <summary>
	///Business class for Financial Transaction Page. 
	///It supports loading of Journal Entries which the user has access to.
    /// -------------------------------------------------------------------------------------------
    /// 05/15/2008 - added sorting for journalEntryGrid on financialtransaction page - trackIt 7690
    /// -------------------------------------------------------------------------------------------
    /// </summary>
	public class JournalEntryDetails: BO.BusinessObject
	{
		#region Constants (Private)
		private const string JournalEntrySPName		= "GetJournalEntryDetails";
		private const string DomainUserId			= "@domainUserId";
		private const string JournalNumber			= "@journalNumber";
		private const string StartDate				= "@startDate";
		private const string EndDate				= "@endDate";
		private const string FundNumber			= "@fundnumber";
        private const string AccountNumber = "@accountnumber";

		private const string JournalEntryKey		= "JournalEntryKey_48c58ca0-17db-4ce4-8d13-63b3c62dac9f";
		//Used in SendByEmail Functionality
		private const string InsertPageQuerySPName	= "InsertPageQuery";
		private const string InsertQuery			= "@query";
        private const string DefaultSortColumn = "JournalId";
        #endregion
		
		#region Enum StoredPROCArguments
		/// <summary>
		/// The StoredPROCArguments enumeration defines values 
		/// for indexing the stored procedure arguments 
		/// and total number of arguments passed to the 
		/// Stored procedure
		/// </summary>
		private enum StoredPROCArguments 
		{
			DomainUserID ,
			JournalID	,
			StartDate  ,
			EndDate ,
			FundNumber,
            AccountNumber,
			//Number of arguments which pass to the stored procedure
			TotalArguments
		}
		#region Enum DataColumns
		/// <summary>
		/// The DataColumns enumeration defines values 
		/// for indexing columns
		/// </summary>
		private enum DataColumns 
		{
			JournalID		,
			Description		,
			FundNumber		,
			AccountNumber	,
			AccountDescription ,
			Amount			,
			PostedBy		
		}
		#endregion
		#endregion

		#region Instance Variables
		private string			currentDataTableName	= Constants.JournalEntryDataTableName;
		private Hashtable		journalEntryDetailsMap	= new Hashtable();
        private bool            sortAscending           = true;
        private string          sortColumn              = DefaultSortColumn;	// Keep this in sync with what the stored proc orders by.
        #endregion

		#region Public Properties

		/// <summary>
		/// Get the JournalId from the JournalEntry datatable which contains only one row.
		/// Returns an empty string if there is no JournalId in the first row
		/// </summary>
		public string JournalID
		{
			get
			{
				DataTable journalTable = DataContainer.Tables[Constants.JournalEntryDataTableName];
				object o = journalTable.Rows.Count > 0 ?journalTable.Rows[0] [(int)DataColumns.JournalID]:null;
				return (o == DBNull.Value ||o == null ) ? string.Empty : (string)o;
			}
		}
		/// <summary>
		/// Get the key to be used in all caching operations for this instance of the object.
		/// </summary>
		public static string CacheKey	{ get { return JournalEntryKey; } }

		/// <summary>
		/// Get the total number of journal entry rows in the data container.
		/// Returns 0 if there is no data in the data container
		/// </summary>
		public int Count
		{
			get { return (DataContainer.Tables.Count == 0) ? 0 : DataContainer.Tables[currentDataTableName].Rows.Count; }
		}

        /// <summary>
        /// Gets the total amount of the collected journal entries.
        /// Returns 0 if no journal entry data is available.
        /// </summary>
        public decimal TotalAmount
        {
            get { return (DataContainer.Tables.Count == 0) ? 0 : (decimal)DataContainer.Tables["Total"].Rows[0]["TotalAmount"]; }
        }

        /// <summary>
        /// Get the sort sequence.
        /// </summary>
        public bool SortAscending
        {
            get { return sortAscending; }
        }

        /// <summary>
        /// Get the name of the sort column.
        /// </summary>
        public string SortColumn
        {
            get { return sortColumn; }
        }

        #endregion

		#region Class Methods
//		/// <summary>
//		/// Gets the Journal Entry object from the cache
//		/// </summary>
//		/// <returns>instance of Journal Entry Details</returns>
//		public static JournalEntryDetails GetCachedObject()
//		{
//			return CachePolicy.GetCachedObject(JournalEntryKey) as JournalEntryDetails;
//		}
		/// <summary>
		/// This method is used in SendByEmail functionality. 
		/// Inserts the current Journal Entry information and the method returns the last inserted ID 
		/// </summary>
		/// <returns>last inserted ID returned by the stored procedure</returns>
		public static int GetQueryId(string query )
		{
			return Convert.ToInt32(Utility.DataAccess.ExecuteScalar(Utility.DataAccess.GetConnectionString(),InsertPageQuerySPName,
				Utility.DataAccess.BuildSqlParameterArray(InsertQuery,SqlDbType.VarChar,query)));
			}
		/// <summary>
		/// Get the list of journal objects bound by a start and end index. These indeces are into the list of journal
		/// entry details that was loaded during the Load() method execution into the data container. Typically, the start index
		/// is on a "page" boundary, where the "page" referes to a datagrid page.
		/// Note that the total number of journal objects returned may be less than the requested count.
		/// We maintain a Hashtable of ArrayList objects using the start index as the key. This allows us to retrieve the
		/// set of Journal objects associated with that index, thereby directly supporting random access based the
		/// page index.
		/// If such an ArrayList does not exist for the current page index, we load them using the list of journal IDs.
		/// The start end end indeces into that list are computed based on the current page index and the datagrid page size.
		/// Journal objects are loaded based on the summaries which falls within the compute start and end indeces, 
		/// and saved in an ArrayList. That ArrayList is then stored in the Hashtable with the current page index as its
		/// key.
		/// </summary>
		/// <param name="startIndex">Index within the journal Entry Details list to begin at</param>
		/// <param name="count">Total number of journal objects to load</param>
		/// <returns>The list of journal objects</returns>
		public  ArrayList GetJournalEntryList(int startIndex, int count)
		{
			ArrayList journalEntryList = journalEntryDetailsMap[startIndex] as ArrayList;
			if (journalEntryList == null)
			{
				journalEntryList = new ArrayList();
				DataTable dataTable = DataContainer.Tables[currentDataTableName];
				for (int i = startIndex, end = Math.Min(i + count, dataTable.Rows.Count); i < end; ++i)
					journalEntryList.Add(new JournalEntryDetail(CachePolicy, dataTable.Rows[i]));
				journalEntryDetailsMap[startIndex] = journalEntryList;
			}
			return journalEntryList;
		}

        public void Sort(string columnName)
        {

            journalEntryDetailsMap.Clear();

            sortAscending = (sortColumn == columnName) ? !sortAscending : true;
            sortColumn = columnName;

            DataTable dataTable = DataContainer.Tables[currentDataTableName];
            DataView dataView = dataTable.DefaultView;
            dataView.Sort = string.Format("{0} {1}", columnName, sortAscending ? Constants.SortOrderAscending : Constants.SortOrderDescending);

            DataTable sortedDataTable = dataTable.Clone();
            foreach (DataRowView rowView in dataView)
                sortedDataTable.ImportRow(rowView.Row);

            DataContainer.Tables.Remove(currentDataTableName);
            DataContainer.Tables.Add(sortedDataTable);
        }

        #endregion
	
		#region Constructor
		/// <summary>
		/// Initializes the base class with the specified cache policy and 
		/// also initialize the DataContainer
		/// </summary>
		public JournalEntryDetails() : base(null)
		{
			DataContainer = new DataSet();
		}
		#endregion
	
		#region Business Object Methods
		/// <summary>
		/// Load the Journal Entry data for the current user. 
		/// The method expects 2 paramters
		/// a) Domain User Id
		/// b) Journal Number
		/// Throws an exception if an error is encountered during the load process.
		/// </summary>
		/// <param name="connectionString">database connection string </param>
		/// <param name="args">arguments to load the journal entry data</param>
		public override void Load(string connectionString, params object[] args)
		{
			if (args.Length != (int)StoredPROCArguments.TotalArguments)
				throw new Exception("Financial Transaction  load requires " 
					+ StoredPROCArguments.TotalArguments.ToString()
					+ "  parameters");
			try 
			{
				DataContainer.Reset();
				Utility.DataAccess.LoadDataSet(DataContainer, Constants.JournalEntryDataTableName, connectionString
					,JournalEntrySPName,
					Utility.DataAccess.BuildSqlParameterArray(
					DomainUserId, SqlDbType.Int	, args[(int)StoredPROCArguments.DomainUserID]
					,JournalNumber, SqlDbType.VarChar, args[(int)StoredPROCArguments.JournalID]
					,StartDate, SqlDbType.VarChar, args[(int)StoredPROCArguments.StartDate]
					,EndDate, SqlDbType.VarChar, args[(int)StoredPROCArguments.EndDate]
					,FundNumber, SqlDbType.VarChar, args[(int)StoredPROCArguments.FundNumber]
                    ,AccountNumber , SqlDbType.VarChar, args[(int)StoredPROCArguments.AccountNumber]
					));

                DataTable total = new DataTable("Total");

                // Create the total by creating an in memory table with a column for the total.  Then create 
                // a data row, compute the total for the amount column in the row and add the row to the table.
                total.Columns.Add(new DataColumn("TotalAmount", System.Type.GetType("System.Decimal")));

                if (DataContainer.Tables[Constants.JournalEntryDataTableName].Rows.Count > 0)
                {
                    DataRow dataRow = total.NewRow();
                    dataRow["TotalAmount"] = (decimal)DataContainer.Tables[Constants.JournalEntryDataTableName].Compute("sum(Amount)","");
                    total.Rows.Add(dataRow);
                }

                DataContainer.Tables.Add(total);
			}
			catch (Exception ex)
			{
				DataContainer = null;
				throw(new Exception(String.Format("{0} {1}",Utility.ExceptionReport.GetExceptionInfo(ex, false),"Error occurred while loading Journal Entry Details"),ex));
			}
		}
		#endregion
		
		
	}
}
